<?php
header('Content-type: text/plain');

require_once('frontstart.inc.php');   # defines: $options[], $context

class Application {
    function handle_request ($options) {
        try {
            ################################################################
            # Validate the Input Parameters
            ################################################################
            if (! isset($_REQUEST['database'])) throw new \Exception('ERROR: the "database" parameter must be supplied');
            $database  = $_REQUEST['database'];
            if (! preg_match('/^[a-zA-Z0-9_]+$/', $database)) throw new \Exception('ERROR: the "database" parameter contains illegal characters (must be letters, digits, and underscores)');
            
            if (! isset($_REQUEST['schema'])) throw new \Exception('ERROR: the "schema" parameter must be supplied');
            $schema  = $_REQUEST['schema'];
            if (! preg_match('/^[a-zA-Z0-9_]+$/', $schema)) throw new \Exception('ERROR: the "schema" parameter contains illegal characters (must be letters, digits, and underscores)');
            
            if (! isset($_REQUEST['table'])) throw new \Exception('ERROR: the "table" parameter must be supplied');
            $table   = $_REQUEST['table'];
            if (! preg_match('/^[a-zA-Z0-9_]+$/', $table)) throw new \Exception('ERROR: the "table" parameter contains illegal characters (must be letters, digits, and underscores)');
            
            if (isset($_REQUEST['view'])) {
                $view   = $_REQUEST['view'];
                if (! preg_match('/^[a-zA-Z0-9_\\.]+$/', $view))
                    throw new \Exception('ERROR: the "view" parameter contains illegal characters (must be letters, digits, underscores, and periods)');
                $view_elements = explode('.', $view);
                $num_view_elements = count($view_elements);
                if ($num_view_elements < 3 || $num_view_elements > 4)
                    throw new \Exception('ERROR: the "view" parameter must be of the form "{db}.{schema}.{table}" or "{db}.{schema}.{table}.{view}"');
            }
            else {
                $view = "$database.$schema.$table";
            }
            
            $neat    = (isset($_REQUEST['neat']) && $_REQUEST['neat']) ? 1 : 0;

            ################################################################
            # Get the main table definition
            ################################################################
            $context = App::context($options);
            $db = $context->database($database);

            # Load extra columns from selected relationships
            $get_table_options = Array();
            if (isset($_REQUEST['relationships']) && $_REQUEST['relationships']) {
                $get_table_options['relationships'] = $_REQUEST['relationships'];
            }
            $get_table_options['view'] = $view;

            $aggregate = (isset($_REQUEST['aggregate']) && $_REQUEST['aggregate'] && $_REQUEST['aggregate'] != 'false') ? $_REQUEST['aggregate'] : 0;
            if ($aggregate) $get_table_options['aggregate'] = $aggregate;

            $table_def = $db->get_table_def($table, $schema, $get_table_options);

            ################################################################
            # The "table" is defined by an SQL statement
            ################################################################

            ################################################################
            # NOTE: The following code supposed that an SQL-based definition could have no paging.
            #       Therefore, since a query must be executed to get the metadata, we might as well execute the whole query
            #       and return the whole data set.
            ################################################################
            # if (isset($table_def['sql'])) {
            #     $sql = $table_def['sql'];
            #     $query_options = array('query_def' => 1);
            #     $data = $db->get_hashes($sql, null, null, $query_options);
            #     $query_def = $query_options['query_def'];
            #     $query_def['data'] = $data;
            #     $table_def = $query_def;
            # }

            ################################################################
            # NOTE: The current thinking is that an SQL-based definition could still have paging.
            #       Therefore, since a query must be executed to get the metadata, we must execute the smallest query possible.
            #       Then we return the SQL in the table_def but not the data itself.
            ################################################################
            if (isset($table_def['sql'])) {
                $sql = $table_def['sql'];
                $db->remove_limit_clause($sql);
                $query_options = array('query_def' => 1, 'limit' => 1);
                $datarow = $db->get_hash($sql, null, null, $query_options);
                $query_def = $query_options['query_def'];
                $db->remove_limit_clause($sql);
                $query_def['sql'] = $sql;
                $query_def['table_name']  = $table_def['table_name'];
                $query_def['table_label'] = $table_def['table_label'];
                $table_def = $query_def;
            }
            else {
                ################################################################
                # Add the list of column names in order
                ################################################################
                if (!isset($table_def['columns'])) {
                    $columns = Array();
                    if (isset($table_def['column'])) {
                        $column_defs = $table_def['column'];
                        foreach ($column_defs as $column_name => $column_def) {
                            $columns[] = $column_name;
                        }
                    }
                    $table_def['columns'] = $columns;
                }
                else {
                    $columns =& $table_def['columns'];
                    if (isset($table_def['column'])) {
                        $column_defs = $table_def['column'];
                        foreach ($column_defs as $column_name => $column_def) {
                            if (! in_array($column_name, $columns)) {
                                #if (! isset($column_def['hidden']) || ! $column_def['hidden']) {
                                #    $columns[] = $column_name;
                                #}
                                if (isset($column_def['agg_dbexpr']) && $column_def['agg_dbexpr']) {
                                    $columns[] = $column_name;
                                }
                            }
                        }
                    }
                }

                ################################################################
                # Add the list of relationship names in order
                ################################################################
                if (!isset($table_def['relationships'])) {
                    if (isset($table_def['relationship'])) {
                        $relationship_defs = $table_def['relationship'];
                        $relationships = Array();
                        foreach ($relationship_defs as $relationship_alias => $relationship_def) {
                            $relationships[] = $relationship_alias;
                        }
                        $table_def['relationships'] = $relationships;
                    }
                }
            }

            ################################################################
            # Encode and return the data structure
            ################################################################
            $json = json_encode($table_def);
            if ($neat) {
                $json = preg_replace('/\\},\\{/', "},\n {", $json);
                $json = preg_replace('/\\],\\[/', "],\n [", $json);
                $json = preg_replace('/,("[A-Za-z_][A-Za-z0-9_]*":[\\{\\}\\[\\]])/', ",\n\\1",  $json);
            }
            echo $json . "\n";
        }
        catch (Exception $e) {
            $this->return_json_error($e->getMessage());
        }
        return(null);
    }

    function return_json_error ($message) {
        if (preg_match("/\n/",$message)) {
            $message = preg_replace("/ *\n */"," ",$message);
        }
        if (preg_match("/\\'/",$message)) {
            $message = preg_replace("/\\'/","\\'",$message);
        }
        echo "{\n";
        echo "    'success': false,\n";
        echo "    'msg': '$message'\n";
        echo "}\n";
    }
}

$application = new Application();
$application->handle_request($options);

